import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  Input,
  OnDestroy,
  OnInit,
  TemplateRef,
  ViewEncapsulation,
} from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { InputBoolean } from '../core/utils/convert';
import { LvConfig } from '../core/config';
import { CascaderOption } from './interface';
import { CascaderService } from './cascader.service';

@Component({
  selector: 'lv-cascader-option',
  templateUrl: './cascader-option.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    class: 'lv-cascader-option',
  },
})
export class CascaderOptionComponent implements OnInit, OnDestroy {
  @Input() lvIndex: number = 0;

  @Input() lvData: CascaderOption;

  @Input() @InputBoolean() lvActive = false;

  @Input() lvItemTemplate: TemplateRef<any>;

  @Input() @InputBoolean() lvLazyLoad: boolean; // NEED_DO

  @Input() lvTrigger: 'click' | 'hover' = 'click';

  @Input() @InputBoolean() lvChangeOnSelect = false; // 点击每层选项时，值都会发生变化，允许选择父级选项

  isLeaf: boolean;

  destroy$ = new Subject<void>(); // NEED_DO: 使用逻辑

  public assetsPrefixPath = LvConfig.assetsPrefixPath;

  constructor(
    private cascaderService: CascaderService,
    private cdr: ChangeDetectorRef,
  ) {}

  get multiple(): boolean {
    return this.cascaderService.isMultipleMode();
  }

  get selected(): boolean {
    const lastValue = this.lvData.selected;
    if (this.isLeaf) {
      return this.lvData.selected;
    }
    this.lvData.selected = this.lvData.children.some((item): boolean => item.selected);
    if (lastValue !== this.lvData.selected) {
      this.cascaderService.refresh$.next();
    }
    return this.lvData.selected;
  }

  get isCheckAll(): boolean {
    const checkChildren = (options: CascaderOption[]): boolean => {
      for (const option of options) {
        if (option.isLeaf) {
          if (!option.disabled && !option.selected) {
            return false;
          }
        } else if (!checkChildren(option.children)) {
          return false;
        }
      }
      return true;
    };
    return checkChildren(this.lvData.children);
  }

  get indeterminate(): boolean {
    const lastValue = this.lvData.indeterminate;
    if (this.isLeaf) {
      this.lvData.indeterminate = false;
    } else {
      const childSelectedLen = this.lvData.children.filter(
        (item): boolean => !item.disabled && !item.indeterminate && item.selected,
      ).length;
      this.lvData.indeterminate = !!childSelectedLen && childSelectedLen !== this.lvData.children.length;
    }
    if (lastValue !== this.lvData.indeterminate) {
      this.cascaderService.refresh$.next();
    }
    return this.lvData.indeterminate;
  }

  ngOnDestroy(): void {
    this.destroy$.complete();
  }

  clickCheckBox(): void {
    if (this.isLeaf) {
      return;
    }
    this.triggerCheckbox();
  }

  clickItem(): void {
    this.cascaderService.unfoldColumn(this.lvData, this.lvIndex, this.lvLazyLoad);

    if (this.lvChangeOnSelect && !this.multiple) {
      this.cascaderService.setSelection();
    }
  }

  clickLeaf(): void {
    if (this.lvData.disabled) {
      return;
    }

    // 点击搜索值
    if (this.cascaderService.searching) {
      this.clickSearchNode();
    } else {
      this.clickDefaultNode();
    }
  }

  clickSearchNode(): void {
    // NEED_DO: 搜索多选
    if (!this.multiple) {
      this.cascaderService.setSearchActive(this.lvData);
      this.cascaderService.setSelectionBySearch(this.lvData.path);
      this.cascaderService.closePanel();
    }
  }

  clickDefaultNode(): void {
    this.cascaderService.unfoldColumn(this.lvData, this.lvIndex, false);
    if (!this.multiple) {
      this.cascaderService.setSelection();
      this.cascaderService.closePanel();
    } else if (this.isLeaf) {
      this.triggerCheckbox();
    }
  }

  ngOnInit(): void {
    if (this.lvLazyLoad) {
      this.isLeaf = !!this.lvData.isLeaf;
    } else {
      // 当不是懒加载时，可以通过children是否为空来判断是否为叶子节点
      this.isLeaf = this.lvData.isLeaf || !this.lvData.children?.length;
    }
    this.cascaderService.refresh$.pipe(takeUntil(this.destroy$)).subscribe((): void => this.cdr.markForCheck());
  }

  private triggerCheckbox(): void {
    const updateSelected = (option: CascaderOption, selected: boolean): void => {
      option.children?.forEach((item): void => {
        updateSelected(item, selected);
      });
      if (!option.disabled) {
        option.selected = selected;
      }
    };
    if (this.isLeaf) {
      this.lvData.selected = !this.lvData.selected;
    } else {
      updateSelected(this.lvData, !this.isCheckAll);
    }
    this.cascaderService.refresh$.next();
  }
}
